# -*- coding: utf-8 -*-
# created on 2016/05/17

# 求不含参数函数零点个数- 导数法 + 区间划分法 + Mathematica 求解法
# 求含参数函数零点个数 - Mathematica 求解法 + 特殊值法

from __future__ import division
from itertools import chain
from sympy import Union, S
from mathsolver.functions.base import BaseFunction, BasePieceFunc, BaseSymbolValue, new_latex
from mathsolver.functions.hanshu.helper import check_func, cal_canshu_from_expr
from mathsolver.functions.hanshu.lingdian_geshu_buhancan import LingDianGeShuBuHanCan
from mathsolver.functions.hanshu.lingdian_geshu_hancan import LingDianGeShuHanCan


class LingDianGeShu(BaseFunction):
    """求函数零点个数（含参+不含参）
    
    1. 不含参函数- 导数法 + 区间划分法 + Mathematica 求解法
    2. 含参函数 - Mathematica 求解法 + 特殊值法
    
    输入：args[0] BaseEq 或者 BaseFunc 或者 BasePiecefunc
        args[1] optional 区间
    """
    canshu = None

    def solver(self, *args):
        # 计算是否含有参数
        func = check_func(args[0])
        expr, var = func.expression, func.var

        if isinstance(func, BasePieceFunc):
            canshu_symbol = list(set(chain(*[expr_1.free_symbols for expr_1, _ in expr])) - {var})
        else:
            canshu_symbol = list(expr.free_symbols - {var})

        has_canshu = bool(canshu_symbol)
        if has_canshu:
            solver = LingDianGeShuHanCan(self.known).solver(*args)
            self.canshu = solver.canshu
            return solver
        else:
            return LingDianGeShuBuHanCan(self.known).solver(*args)


class LingDianGeShuQiuCan(BaseFunction):
    """利用导数解决函数零点求参数 - Mathematica 暴力求解 + 特殊值法

    输入：args[0] BaseEq 或者 BaseFunc
         args[1] optional BaseNumber
         args[2] optional "有","没有"
         args[3] optional 区间"""

    def solver(self, *args):
        # 补充：兼容 2 个输入, BaseFunc, BaseNumber
        if len(args) == 2:
            args += None, None
        else:
            assert len(args) == 4

        # 处理输入
        func = check_func(args[0])
        expr, var = func.expression, func.var
        canshu = cal_canshu_from_expr(expr)

        if args[1]:
            count = args[1].sympify()
        elif "没有" in args[2]:
            count = "none"
        else:
            count = "all"

        # 计算含参数函数零点个数
        if args[3]:
            lingdian_solver = LingDianGeShuHanCan(self.known).solver(args[0], args[3])
        else:
            lingdian_solver = LingDianGeShuHanCan(self.known).solver(args[0])

        self.steps.extend(lingdian_solver.steps)
        result = lingdian_solver.output[0].value

        if count == "all":
            output_result = Union(*result.values())
        elif count == "none":
            output_result = S.Reals - Union(*result.values())
        else:
            output_result = result[count]

        self.steps.append(["", "所以当函数有 %s 个零点时，%s ∈ %s" % (count, new_latex(canshu), new_latex(output_result))])
        self.output.append(BaseSymbolValue({canshu: output_result}))
        self.label.add("已知函数零点求参数")
        return self


class ProofLingDianGeShu(BaseFunction):
    """证明函数零点个数"""

    def solver(self, *args):
        geshu = args[1].sympify()
        # 计算零点个数
        lingdian_n = LingDianGeShuQiuCan().solver(*args)
        self.steps.extend(lingdian_n.steps)
        self.steps.append(["", "根据题目条件可知 f(x) 有 %s 个零点" % geshu])
        return self


if __name__ == '__main__':
    pass
